package es.ojugames.myplaces;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import es.ojugames.myplaces.database.ConstantsDB;
import es.ojugames.myplaces.location.CheckLocationServiceActivity;
import es.ojugames.myplaces.location.SeleccionarUbicacionActivity;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.MediaStore;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

//Activity que servira tanto para crear nuevos lugares como
//para editar los existentes

//Extiende Runnable porque se encargara de ejecutar un proceso
//para obtener la localizacion a traves del GPS
public class EditarLugarActivity extends Activity implements Runnable {

	//TextViews donde mostraremos la Latitud y Longitud del Lugar	
	private TextView longitudTextView, latitudTextView;
	//Variables que almacenaran la Latitud y Longitud del lugar que
	//estamos editando
	private Double longitud, latitud;
	//Inputs de la interfaz con el nombre y la descripcion del lugar
	EditText nombreTextView, descripcionTextView;
	
	//Constantes para identificar las respuestas de distintas Activities
	private final int ACTIVITY_MAP = 0;
	private final int ACTIVITY_CAMERA = 1;
	private final int ACTIVITY_GALLERY = 2;
	
	//Vista donde mostraremos la imagen del lugar
	private ImageView imgFoto;
	
	//Uris de la imagen almacenada y modificada para poder borrar la vieja
	//en cambio de que se guarde el cambio
	private String uriFotoStrOld;
	private String uriFotoStrNew;
	
	//Nombre con el que se almacenara la imagen en el sistema
	String image_name;
	
	//Id del lugar que estamos editando
	private Long idPlaces;
	
	//Modo en el que cargamos la activity, "nuevo" o "edicion"
	private String modo;
	
	//Variable donde almacenaremos la posicion que devuelve el GPS
	Location currentLocation = null;
	
	//Dialogo de progreso que se cargara cuando estemos obteniendo
	//la localizacion por GPS
	private ProgressDialog pd;
	
	//Servicio de Localizacion
	private LocationManager locManager;
	//Listener que gestionara los cambios en la posicion
	MyLocationListener mLocationListener;
	
	//Variable de control para inhabilitar botones en caso de error
	boolean control;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		
		//En principio todo correcto
		control = true;
		
		//Obtenemos el servicio de localizacion para poder acceder al GPS
		locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
		
		//Comprobamos en que modo debemos cargar la activity segun nos indique el Intent
		Bundle extras = getIntent().getExtras();
		if(extras != null) {
			modo = extras.getString("modo");
			
		}
		
		//En funcion del Intent llamamos a la funcion que cargara la Activity en consecuencia
		if (modo.equals("nuevo")) {
			cargarModoNuevo();
		} else if (modo.equals("nuevoDesdeMapa")){
			longitud = extras.getDouble("ln");
			latitud = extras.getDouble("lt");
			cargarModoNuevo();
		} else if (modo.equals("edicion")){
			idPlaces = extras.getLong("idPlaces");
			cargarModoEdicion(idPlaces);
		}
		
	}
	
	//Metodo que inicializa la activity en modo edicion
	private void cargarModoEdicion(Long idPlaces) {
		//Cargamos la interfaz de modo edicion
		setContentView(R.layout.edit_place);
		
		//Obtenemos los elementos de la interfaz con los que vamos a interactuar
		longitudTextView = (TextView) this.findViewById(R.id.longitud);
		latitudTextView = (TextView) this.findViewById(R.id.latitud);
		nombreTextView = (EditText) this.findViewById(R.id.nombreLugarForm);
		descripcionTextView = (EditText) this.findViewById(R.id.descripcionLugarForm);
		imgFoto = (ImageView) findViewById(R.id.imgFoto);
		
		//Al estar en modo edicion es necesario obtener los datos
		//del lugar a editar
		
		//Obtenemos el cursor con los datos necesarios a partir de la uri del lugar
		Uri uri = Uri.parse("content://es.ojugames.myplaces/places/" + idPlaces);
		Cursor cursor = getContentResolver().query(uri, null, null, null, null);
		
		//Obtenemos los indices de las columnas a consultar
		int indexNombre = cursor.getColumnIndex(ConstantsDB.Places.NOMBRE);
		int indexDescripcion = cursor.getColumnIndex(ConstantsDB.Places.DESCRIPCION);
		int indexFoto = cursor.getColumnIndex(ConstantsDB.Places.FOTO);
		int indexLon = cursor.getColumnIndex(ConstantsDB.Places.LONGITUD);
		int indexLat = cursor.getColumnIndex(ConstantsDB.Places.LATITUD);
		
		//Comprobamos que al menos existe un registro en caso contrario mostramos
		//que se ha produccido un error
		if (cursor.moveToFirst()) {
			//Obtenemos los datos a editar
			String nombre =  cursor.getString(indexNombre);
			String descripcion = cursor.getString(indexDescripcion);
			longitud = new Double(cursor.getString(indexLon));
		    latitud = new Double(cursor.getString(indexLat));
			
		    //Duplicamos la informacion para poder borrar la foto antigua
			//en caso de ser modificada
			uriFotoStrOld = cursor.getString(indexFoto);
			uriFotoStrNew = cursor.getString(indexFoto);
			
			//Cargamos en la interfaz los datos
			Uri uriFoto = Uri.parse(uriFotoStrOld);
			nombreTextView.setText(nombre);
			descripcionTextView.setText(descripcion);
			latitudTextView.setText(getText(R.string.latitud) + ": " + latitud.toString());
	        longitudTextView.setText(getText(R.string.longitud) + ": " + longitud.toString());
			imgFoto.setImageURI(uriFoto);
			
			//Generamos un nombre para la imagen a almacenar a partir de la fecha y hora
			image_name = android.text.format.DateFormat.format("yyyyMMdd_hhmmss", new java.util.Date()).toString();
			
		} else {
			//Mostramos que se ha producido un error
			nombreTextView.setText(R.string.errorBD);
			descripcionTextView.setText(R.string.errorBD);
			latitudTextView.setText(R.string.latitud + ": " + R.string.errorBD);
	        longitudTextView.setText(R.string.longitud + ": " + R.string.errorBD);
		    imgFoto.setImageResource(R.drawable.no_image);
		    
		    //Los datos no han sido cargados correctamente
		    control = false;
		}
	}

	//Metodo que inicializa la activity en modo nuevo
	private void cargarModoNuevo() {
		//Generamos un nombre para la imagen a almacenar a partir de la fecha y hora
		image_name = android.text.format.DateFormat.format("yyyyMMdd_hhmmss", new java.util.Date()).toString();
		
		//Cargamos la interfaz de modo nuevo
		setContentView(R.layout.create_place);
		
		//Obtenemos los elementos de la interfaz con los que vamos a interactuar
		longitudTextView = (TextView) this.findViewById(R.id.longitud);
		latitudTextView = (TextView) this.findViewById(R.id.latitud);
		nombreTextView = (EditText) this.findViewById(R.id.nombreLugarForm);
		descripcionTextView = (EditText) this.findViewById(R.id.descripcionLugarForm);
		imgFoto = (ImageView) findViewById(R.id.imgFoto);
		
		if (longitud != null && latitud != null){
			latitudTextView.setText(getText(R.string.latitud) + ": " + latitud.toString());
	        longitudTextView.setText(getText(R.string.longitud) + ": " + longitud.toString());
		}
		
	}

	//Metodo que llama a la Camara para obtener una imagen como resultado
	public void irCamara(View v) {
		if (control) {
			Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
			startActivityForResult(i, ACTIVITY_CAMERA);
		}
	}

	//Metodo que llama a la Galeria par obtener una imagen como resultado
	public void irGaleria(View v) {
		if (control) {
			//[DUDA] Creo que hay alternativas para llamar a la galeria
			Intent i = new Intent(Intent.ACTION_PICK);
			i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media.CONTENT_TYPE);
			startActivityForResult(Intent.createChooser(i, getString(R.string.galeria)), ACTIVITY_GALLERY);
		}
	}
	
	//Funcion que valida los datos del formulario
	public boolean validarFormulario() {
		String nombreText = nombreTextView.getText().toString();
		String descripcionText = descripcionTextView.getText().toString();
		
		Boolean res = !nombreText.equals("") && !descripcionText.equals("") && (longitud != null) && (latitud != null)
				&& uriFotoStrNew != null;
		
		res = res && (nombreText.length() <= 30) && (descripcionText.length() <= 200);
		
		return res;
	}
	
	//Funcion que carga la activity donde seleccionaremos la posicion en un mapa
	public void seleccionarUbicacion(View v) {
		Intent intent = new Intent(EditarLugarActivity.this, SeleccionarUbicacionActivity.class);
		
		if (latitud != null && longitud != null) {
			intent.putExtra("lt", latitud);
			intent.putExtra("ln", longitud);
		}
		
		startActivityForResult(intent, ACTIVITY_MAP);
	}
	
	//Metodo que obtiene la posicion actual a partir del GPS
	public void obtenerUbicacion(View v) {
		//Comprobamos que el GPS esta disponible
		if (locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			//En caso de que el GPS este disponible cargamos un dialogo de carga mientras
			//obtenemos la localizacion a partir del proceso que ejecutamos
			DialogInterface.OnCancelListener dialogCancel = new DialogInterface.OnCancelListener() {
				public void onCancel(DialogInterface dialog) {
					Toast.makeText(getBaseContext(), 
						getResources().getString(R.string.gps_signal_not_found), 
                        Toast.LENGTH_LONG).show();
					handler.sendEmptyMessage(0);
				}
			};
			pd = ProgressDialog.show(this, this.getResources().getString(R.string.search), 
					this.getResources().getString(R.string.search_signal_gps), true, true, dialogCancel);
			Thread thread = new Thread(this);
			thread.start();
		} else {
			//En caso de que el GPS este desactivdo informamos mediante una activity que da
			//acceso a la pantalla de configuracion
			Intent intent = new Intent(EditarLugarActivity.this, CheckLocationServiceActivity.class);
	    	startActivity(intent);
	    }
	}

	//Proceso que obtiene la localizacion mediante GPS
	public void run() {
		Looper.prepare();
			
		mLocationListener = new MyLocationListener();
			
		locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocationListener);
		Looper.loop(); 
		Looper.myLooper().quit();
	}
	
	//Manejador para que actuara en caso de cambios de posicion
	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			pd.dismiss();
			locManager.removeUpdates(mLocationListener);
	    	if (currentLocation != null) {
	    		fijarUbicacion(currentLocation);
	    	}
		}
	};
	
	//Listener para detectar los cambios en la localizacion
	private class MyLocationListener implements LocationListener {
        public void onLocationChanged(Location loc) {
        	currentLocation = loc;
            handler.sendEmptyMessage(0);
        }

		public void onProviderDisabled(String provider) {
		}

		public void onProviderEnabled(String provider) {
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
		}
	} 
	
	//Mostramos por pantalla la localizacion obtenida y almacenamos
	//luego la latitud y longitud
	public void fijarUbicacion(Location loc) {
		if(loc != null) {
			longitud = new Double(loc.getLongitude() * 1E6);
			latitud = new Double(loc.getLatitude() * 1E6);
			latitudTextView.setText(getText(R.string.latitud) + ": " + latitud.toString());
	        longitudTextView.setText(getText(R.string.longitud) + ": " + longitud.toString());
	    }
	    else {
	    	//Si el GPS no devuelve datos avisamos al respecto
	    	longitudTextView.setText(R.string.no_datos);
	    	latitudTextView.setText(R.string.no_datos);
	    }
	}
	
	//Metodo que gestiona las respuestas de las activities
	@Override 
	public void onActivityResult(int requestCode, int resultCode, Intent data) {     
	  super.onActivityResult(requestCode, resultCode, data); 
	  
	  OutputStream outStream = null;
	  File file = null;
	  
	  //Comprobamos que la Tarjeta SD esta montada y en caso contrario informamos
	  String state = Environment.getExternalStorageState();
	  if (!state.equals(Environment.MEDIA_MOUNTED)){
		  Toast.makeText(this, getText(R.string.sd_no_montada), Toast.LENGTH_LONG).show();
	  } else {
		  //Comprobamos que el directorio para almacenar las imagenes existe y si no
		  //es asi lo creamos
		  File dir = new File(Environment.getExternalStorageDirectory().toString() + "/MyPlaces");
		  
		  if (!dir.exists()) {
			dir.mkdirs();
		  }

		  //Evita que la galeria indexe las imagenes de la aplicacion
		  File noMedia = new File(dir, ".nomedia");
		  if (!noMedia.exists()) {
			  try {
				noMedia.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		  }
		  
		  //Creamos el archivo donde almacenaremos la foto
		  file = new File(dir, image_name + ".png");
		  
		  try {
			outStream = new FileOutputStream(file);
		  } catch (FileNotFoundException e1) {
			 e1.printStackTrace();
		  }
	  }
	  
	  //Comprobamos que Actitiy es la que nos responde
	  switch(requestCode) { 
	    case ACTIVITY_MAP: 
	    	//Mostramos por pantalla la localizacion obtenida y la almacenamos
	    	if (resultCode == Activity.RESULT_OK) { 
	    	  	longitud = data.getDoubleExtra("ln", new Double(0));
				latitud = data.getDoubleExtra("lt", new Double(0));
				latitudTextView.setText(getText(R.string.latitud) + ": " + latitud.toString());
		        longitudTextView.setText(getText(R.string.longitud) + ": " + longitud.toString());
            }
	      	break; 
	    case ACTIVITY_CAMERA:
	    	if (resultCode != RESULT_CANCELED && state.equals(Environment.MEDIA_MOUNTED)) {
	    		//Si la activity nos devuelve una imagen de la camara
				
	    		//La escalamos y la comprimimos en PNG y la guardamos
	    		Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
				Bitmap resized = Bitmap.createScaledBitmap(thumbnail, 300, 225,
						false);
				resized.compress(Bitmap.CompressFormat.PNG, 100, outStream);

				try {
					outStream.flush();
					outStream.close();
				} catch (Exception ex) {
					ex.printStackTrace();
				}

				//Obtenemos la uri de la foto almacenada
				uriFotoStrNew = file.getPath();
				//Mostramos la imagen por pantalla
				//imgFoto.setImageBitmap(resized);
				//[DUDA] Por alguna razon la imagen se escala al utilizar el metodo anterior desde la camara
				imgFoto.setImageURI(Uri.parse(uriFotoStrNew));
			}
			break;
	    case ACTIVITY_GALLERY:
	    	if (resultCode != RESULT_CANCELED && state.equals(Environment.MEDIA_MOUNTED)) {
				//Procedemos de manera analoga para el caso de la galeria
	    		Uri selectedImageUri = data.getData();

				Bitmap bitmap = null;

				try {
					bitmap = MediaStore.Images.Media.getBitmap(
							this.getContentResolver(), selectedImageUri);
				} catch (Exception e) {
					e.printStackTrace();
				}

				Bitmap resized = Bitmap.createScaledBitmap(bitmap, 300, 225,
						false);

				resized.compress(Bitmap.CompressFormat.PNG, 100, outStream);

				try {
					outStream.flush();
					outStream.close();
				} catch (Exception ex) {
					ex.printStackTrace();
				}

				uriFotoStrNew = file.getPath();
				imgFoto.setImageBitmap(resized);
			}
	    	break;
	  } 
	}

	//Metodo que guarda en BD los datos modificados
	public void guardar(View v) {
		if (control){
			Uri uri = Uri.parse("content://es.ojugames.myplaces/places/" + idPlaces);
			ContentValues place = new ContentValues();

			//Comprobamos que los datos introducidos son validos
			if (validarFormulario()) {
				//en caso afirmativo los almacenamos en base de datos y finalizamos
				
				String nombre = nombreTextView.getText().toString();
				String descripcion = descripcionTextView.getText().toString();
				String lat = latitud.toString();
				String lon = longitud.toString();

				place.put(ConstantsDB.Places._ID, idPlaces);
				place.put(ConstantsDB.Places.NOMBRE, nombre);
				place.put(ConstantsDB.Places.DESCRIPCION, descripcion);
				place.put(ConstantsDB.Places.LATITUD, lat);
				place.put(ConstantsDB.Places.LONGITUD, lon);
				place.put(ConstantsDB.Places.FOTO, uriFotoStrNew);

				getContentResolver().update(uri, place, null, null);

				//Si la foto ha sido cambiada borramos la antigua
				if (!uriFotoStrNew.equals(uriFotoStrOld)){
					File image = new File(uriFotoStrOld);
					image.delete();
				}
				
				Toast.makeText(getApplicationContext(),
						R.string.punto_editado,
						Toast.LENGTH_SHORT).show();
				
				//Informamos de que se ha borrado para que la Acvity que muestra
				//los detalles actue en consecuencia
				Intent i = new Intent();
				i.putExtra("type", "update");
				setResult(RESULT_OK, i);
				
				finish();
			} else {
				//en caso negativo informamos
				Toast.makeText(getApplicationContext(),
						R.string.datos_no_validos,
						Toast.LENGTH_SHORT).show();
			}
		}
	}
	
	//Metodo que guarda en BD el nuevo Lugar
	public void crear(View v) {
		Uri uri = Uri.parse("content://es.ojugames.myplaces/places");
		ContentValues place = new ContentValues();

		if (validarFormulario()) {
			String nombre = nombreTextView.getText().toString();
			String descripcion = descripcionTextView.getText().toString();
			String lat = latitud.toString();
			String lon = longitud.toString();
		
			place.put(ConstantsDB.Places.NOMBRE, nombre);
			place.put(ConstantsDB.Places.DESCRIPCION, descripcion);
			place.put(ConstantsDB.Places.LATITUD, lat);
			place.put(ConstantsDB.Places.LONGITUD, lon);
			place.put(ConstantsDB.Places.FOTO, uriFotoStrNew);

			getContentResolver().insert(uri, place);

			Toast.makeText(getApplicationContext(),
				R.string.punto_creado,
				Toast.LENGTH_SHORT).show();

			finish();
		} else {
			//en caso negativo informamos
			Toast.makeText(getApplicationContext(),
					R.string.datos_no_validos,
					Toast.LENGTH_SHORT).show();
		}
	}
	
	//Controlamos que al cancelar la creacion o edicion no generamos basura
	public void cancelar(View v) {
		
		//Si estamos en modo "nuevo" y cancelamos comprobamos si se ha creado algun archivo y borramos
		if (modo.equals("nuevo")) {
			if (uriFotoStrNew != null){
				File image = new File(uriFotoStrNew);
				image.delete();
			}
		//Si estamos en modo "edicion" y cancelamos comprobamos si se ha cambiado la foto borramos la nueva
		} else if (modo.equals("edicion")){
			if (!uriFotoStrNew.equals(uriFotoStrOld)){
				File image = new File(uriFotoStrNew);
				image.delete();
			}
		}
		
		setResult(RESULT_CANCELED);
		finish();
	}
	
	public void eliminar(View v) {
		if (control) {
			//Borramos el registro en BD
			Uri uri = Uri.parse("content://es.ojugames.myplaces/places/" + idPlaces);
			getContentResolver().delete(uri, null, null);
			
			//Y la foto almacenada en el sistema
			if (!uriFotoStrNew.equals(uriFotoStrOld)){
				//Si hemos cambiado la foto borramos la nueva y la existente
				File image = new File(uriFotoStrNew);
				image.delete();
				image = new File(uriFotoStrOld);
				image.delete();
			} else {
				//En caso contrario solo hay que borrar la existente
				File image = new File(uriFotoStrNew);
				image.delete();
			}
			
			//Informamos de que se ha borrado para que la Acvity que muestra
			//los detalles actue en consecuencia
			Intent i = new Intent();
			i.putExtra("type", "delete");
			setResult(RESULT_OK, i);
			
			finish();
		}
	}
	
	public boolean onKeyDown(int keyCode, KeyEvent  event) {
        //Nos aseguramos que al volver no generamos basura
		if(keyCode == KeyEvent.KEYCODE_BACK){
			//Si estamos en modo "nuevo" y cancelamos comprobamos si se ha creado algun archivo y borramos
			if (modo.equals("nuevo")) {
				if (uriFotoStrNew != null){
					File image = new File(uriFotoStrNew);
					image.delete();
				}
			//Si estamos en modo "edicion" y cancelamos comprobamos si se ha cambiado la foto borramos la nueva
			} else if (modo.equals("edicion")){
				if (!uriFotoStrNew.equals(uriFotoStrOld)){
					File image = new File(uriFotoStrNew);
					image.delete();
				}
			}
			
			setResult(RESULT_CANCELED);
			finish();
        	return true;
        }
        
        return false;
	}
}
